package crontask

import (
    "github.com/astaxie/beego/logs"
    "cloud_worm/util/uid"
    "cloud_worm/util/umodels/mysqldb"
    "cloud_worm/util/umodels/mysqldb/dbmanager"
    "cloud_worm/util/umodels/mysqldb/dbtask"
    "fmt"
    "strings"
    "time"
    "cloud_worm/wormweb/controllers/ctrutil"
    "cloud_worm/wormweb/controllers/ctrinner/taskqueue"
    "cloud_worm/wormweb/controllers/ctrsecurity/webtask/fasttask"
)

type CrWeaponTask dbtask.CronTask
/**
 @Description：worm weapon task任务的run接口
 @Param:
 @Return：
 */
func (w CrWeaponTask) Run()  {

    recordID, err := CronWeaponTaskBegin(w)
    if err == nil {
        defer CronWeaponTaskEnd(recordID, w)
    }

    // 必须保证是weapon task
    if w.TaskType != CronWeaponTask {
        logs.Error(fmt.Sprintf("cron weapon task`%s` task type`%d` error.", w.Name, w.TaskType))
        return
    }

    if w.TargetType == ctrutil.TaskForAll {
        t, err := w.createForAll()
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` create task error: %s", w.Name, err.Error()))
            return
        }
        // 更新task
        t.Updated = time.Now().Unix()
        t.Status = ctrutil.WEAPON_TASK_DOING
        err = t.Update("updated", "status")
        if err != nil {
            return
        }
        err = w.execForAll(t)
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` exec task error: %s", w.Name, err.Error()))
            return
        }

    } else if w.TargetType == ctrutil.TaskForApplication {
        t, err := w.createForApply()
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` create task error: %s", w.Name, err.Error()))
            return
        }
        // 更新task
        t.Updated = time.Now().Unix()
        t.Status = ctrutil.WEAPON_TASK_DOING
        err = t.Update("updated", "status")
        if err != nil {
            return
        }
        err = w.execForApply(t)
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` exec task error: %s", w.Name, err.Error()))
            return
        }

    } else if w.TargetType == ctrutil.TaskForMachine {
        t, err := w.createForMachine()
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` create task error: %s", w.Name, err.Error()))
            return
        }
        // 更新task
        t.Updated = time.Now().Unix()
        t.Status = ctrutil.WEAPON_TASK_DOING
        err = t.Update("updated", "status")
        if err != nil {
            return
        }
        err = w.execForMachine(t)
        if err != nil {
            logs.Error(fmt.Sprintf("cron weapon task`%s` exec task error: %s", w.Name, err.Error()))
            return
        }

    } else {
        logs.Error(fmt.Sprintf("cron weapon task`%s` target type`%d` error", w.Name, w.TargetType ))
        return
    }

    return
}

// ------------------- Machine
// @Description：创建任务，并下发任务
func (w CrWeaponTask) createForAll() (*dbtask.WeaponTask, error) {
    wolId := dbmanager.WormId{}
    onlineCount, err := wolId.CountStatus(dbmanager.AgentOnline, ctrutil.RunMode)
    if err != nil {
        return nil, err
    }

    // 准备插入insert
    task := &dbtask.WeaponTask{
        TaskId:      uid.TaskIdProducer().CreateTaskId(),
        TaskOwner:   w.TaskOwner,
        TargetType:  ctrutil.TaskForAll,
        Target:      ctrutil.TaskAllApplication,
        WeaponsName: w.WeaponsName,
        Comment:     fmt.Sprintf("cron task`%s`", w.Name),
        SumCount:    int(onlineCount) * len(strings.Split(w.WeaponsName, ",")),
        Created:     time.Now().Unix(),
        Status:      ctrutil.WEAPON_TASK_NO_DO,
    }
    task.Updated = task.Created

    err = task.Insert()
    if err != nil {
        return nil, err
    }

    return task, nil
}

// @Description：执行
func (w CrWeaponTask) execForAll(task *dbtask.WeaponTask) error {
    wormId := dbmanager.WormId{}
    wolIds, err := wormId.SelectStatus(mysqldb.SelectOffsetZero, mysqldb.SelectLimitAll, dbmanager.AgentOnline, ctrutil.RunMode)
    if err != nil {
        return err
    }

    wpsName := strings.Split(task.WeaponsName, ",")

    sumItem := len(wolIds) * len(wpsName)
    notifyChan := fasttask.WaitTaskFinish(task, sumItem, fasttask.IsNeedTaskAlertDeal(task.WeaponsName))

    for _, m := range wolIds {
        for _, wp := range wpsName {
            taskItem := &fasttask.TaskItem{
                NotifyChan: notifyChan,
                TaskId: task.TaskId,
                WormId: m.AgentId,
                WeaponName: wp,
                Input: "",                              // todo：考虑何时可以设置入参的设计
            }
            //logs.Info(fmt.Sprintf("%s, %s, task: %s", taskItem.WeaponName, taskItem.WolId, taskItem.TaskId))
            taskqueue.FastQueInst().MsgQ.Push(taskItem)
        }
    }

    return nil
}

// ------------------- Machine
// @Description：创建任务，并下发任务
func (w CrWeaponTask) createForApply() (*dbtask.WeaponTask, error) {
    app := &dbmanager.Application{Name: w.Target}
    err := app.Read("name")
    if err != nil {
        return nil, err
    }

    mach := dbmanager.Machine{ApplyId: app.Id}
    machineSize, err := mach.Count(mysqldb.StatusValid, app.Id, mysqldb.SelectStrAll, mysqldb.SelectStrAll)
    if err != nil {
        return nil, err
    }

    // 准备插入insert
    task := &dbtask.WeaponTask{
        TaskId:      uid.TaskIdProducer().CreateTaskId(),
        TaskOwner:   w.TaskOwner,
        TargetType:  ctrutil.TaskForApplication,
        Target:      app.Name,
        WeaponsName: w.WeaponsName,
        Comment:     fmt.Sprintf("cron task`%s`", w.Name),
        SumCount:    int(machineSize) * len(strings.Split(w.WeaponsName, ",")),
        Created:     time.Now().Unix(),
        Status:      ctrutil.WEAPON_TASK_NO_DO,
    }
    task.Updated = task.Created

    err = task.Insert()
    if err != nil {
        return nil, err
    }
    return task, nil
}

/**
 @Description：执行
 */
func (w CrWeaponTask) execForApply(task *dbtask.WeaponTask) error {
    application := &dbmanager.Application{Name: task.Target}
    err := application.Read("name")
    if err != nil {
        return nil
    }

    ma := &dbmanager.Machine{ApplyId: application.Id}
    machines, err := ma.Select(mysqldb.SelectOffsetZero, mysqldb.SelectLimitAll,
        mysqldb.StatusValid, int64(application.Id), mysqldb.SelectStrAll, mysqldb.SelectStrAll)
    if err != nil {
        return err
    }

    // weapon
    wpsName := strings.Split(task.WeaponsName, ",")

    sumItem := len(machines) * len(wpsName)
    notifyChan := fasttask.WaitTaskFinish(task, sumItem, fasttask.IsNeedTaskAlertDeal(task.WeaponsName))

    for _, m := range machines {
        for _, wp := range wpsName {
            taskItem := &fasttask.TaskItem{
                NotifyChan: notifyChan,
                TaskId: task.TaskId,
                WormId: m.WormId,
                WeaponName: wp,
                Input: "",                              // todo：考虑何时可以设置入参的设计
            }
            taskqueue.FastQueInst().MsgQ.Push(taskItem)
        }
    }

    return nil
}

// ------------------- Machine
// @Description：创建任务，并下发任务
func (w CrWeaponTask) createForMachine() (*dbtask.WeaponTask, error) {
    wolId := &dbmanager.WormId{}
    err := wolId.SelectValidByIP(w.Target)
    if err != nil {
        return nil, err
    }

    // 准备插入数据
    task := &dbtask.WeaponTask{
        TaskId:      uid.TaskIdProducer().CreateTaskId(),
        TaskOwner:   w.TaskOwner,
        TargetType:  ctrutil.TaskForMachine,
        Target:      w.Target,
        WeaponsName: w.WeaponsName,
        Comment:     fmt.Sprintf("cron task`%s`", w.Name),
        SumCount:    len(strings.Split(w.WeaponsName, ",")),
        Created:     time.Now().Unix(),
        Status:      ctrutil.WEAPON_TASK_NO_DO,
    }
    task.Updated = task.Created
    err =  task.Insert()
    if err != nil {
        return nil, err
    }

    return task, nil
}

// @Description：执行
func (w CrWeaponTask) execForMachine(task *dbtask.WeaponTask) error {
    machine := &dbmanager.Machine{Ip: task.Target, Status: mysqldb.StatusValid}
    err := machine.Read("ip", "status")
    if err != nil {
        return err
    }

    // weapon
    wpsName := strings.Split(task.WeaponsName, ",")

    sumItem := len(wpsName)
    notifyChan := fasttask.WaitTaskFinish(task, sumItem, fasttask.IsNeedTaskAlertDeal(task.WeaponsName))

    for _, wp := range wpsName {
        taskItem := &fasttask.TaskItem{
            NotifyChan: notifyChan,
            TaskId: task.TaskId,
            WormId: machine.WormId,
            WeaponName: wp,
            Input: "",                              // todo：考虑何时可以设置入参的设计
        }
        taskqueue.FastQueInst().MsgQ.Push(taskItem)
    }

    return nil
}